/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nl.cloudfarming.client.geoviewer.jxmap.map;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;

import org.jdesktop.swingx.JXPanel;

/**
 * DrawingLayerPanel is a JComponent which is used as a layer on the map for
 * painting. For example drawing a rectangle (zoomin) on this panel.
 *
 */
public class DrawingLayerPanel extends JXPanel {

    private static final long serialVersionUID = 5283504191785465148L;
    private static final float SELECTED_AREA_ALPHA = 0.6f;
    private int rectStartX = -1;
    private int rectStartY = -1;
    private int rectWidth = -1;
    private int rectHeight = -1;
    private Color grayedOutColor = Color.DARK_GRAY;
    private final Color outlineColor = Color.WHITE;
    private BufferedImage dragImage;
    private int dragImageX;
    private int dragImageY;
    private boolean paintDragImage;

    public DrawingLayerPanel() {
        setOpaque(false);
        setVisible(false);
    }

    @Override
    public void paintComponent(final Graphics g) {
        final Graphics2D g2 = (Graphics2D) g;
        paintRectangle(g2);
        paintDragImage(g2);
    }

    private void paintRectangle(final Graphics2D g2) {
        if (rectStartX != -1 && rectStartY != -1 && rectWidth != -1 && rectHeight != -1) {
            g2.setColor(grayedOutColor);
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, SELECTED_AREA_ALPHA));

            // top part
            g2.fillRect(0, 0, getWidth(), rectStartY);
            // left part
            g2.fillRect(0, rectStartY, rectStartX, getHeight() - rectStartY);
            // right part
            g2.fillRect(rectStartX + rectWidth, rectStartY, getWidth() - rectStartX - rectWidth, rectHeight);
            // bottom part
            g2.fillRect(rectStartX, rectStartY + rectHeight, getWidth() - rectStartX, getHeight() - rectStartY - rectHeight);

            // draw rectangle around selected area
            g2.setColor(outlineColor);
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
            g2.drawRect(rectStartX, rectStartY, rectWidth, rectHeight);
        }
    }

    private void paintDragImage(final Graphics2D g2) {
        if (paintDragImage) {
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
            g2.drawImage(dragImage, dragImageX, dragImageY, this);
        }
    }

    /**
     * Draws a rectangle on the panel with the specified start point and size.
     * The given rectangle is inverted. Everything not within the given area is
     * grayed out.
     *
     * @param point
     *            the top left x,y of the rectangle (pixels)
     * @param offsetX
     *            the offset-x used (width)
     * @param offsetY
     *            the offset-y used (height)
     */
    public void drawRect(final Point point, final int offsetX, final int offsetY) {
        setVisible(true);

        rectStartX = (int) point.getX();
        rectStartY = (int) point.getY();
        rectWidth = offsetX;
        rectHeight = offsetY;

        if (rectHeight < 0) {
            rectStartY += rectHeight;
            rectHeight = Math.abs(rectHeight);
        }
        if (rectWidth < 0) {
            rectStartX += rectWidth;
            rectWidth = Math.abs(rectWidth);
        }

        repaint();
    }

    /**
     * Removes the current rectangle from the panel (when there's one painted).
     *
     */
    private void clearRect() {
        setVisible(false);

        rectStartX = -1;
        rectStartY = -1;
        rectWidth = -1;
        rectHeight = -1;
        repaint();
    }

    private void clearImage() {
        paintDragImage = false;
    }

    public void hideDrawingPanel() {
        clearRect();
        clearImage();
        setVisible(false);
    }

    public void setColor(final Color color) {
        grayedOutColor = color;
    }

    public void drawImage(final BufferedImage dragImageToPaint, final int x, final int y) {
        dragImage = dragImageToPaint;
        dragImageX = x;
        dragImageY = y;

        paintDragImage = true;
        repaint();
    }
}
